"""
质量评分数据仓库
"""
import logging
from typing import List, Dict, Any, Optional
from datetime import datetime, timedelta
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
from bson import ObjectId
import pymongo

from ..models.quality import ScoreHistory, QualityMetrics, ScoreResult

logger = logging.getLogger(__name__)


class QualityRepository:
    """质量评分数据仓库"""
    
    def __init__(self, mongodb_client: AsyncIOMotorClient, database_name: str = "ai_writing"):
        """
        初始化仓库
        
        Args:
            mongodb_client: MongoDB客户端
            database_name: 数据库名称
        """
        self.client = mongodb_client
        self.db: AsyncIOMotorDatabase = self.client[database_name]
        self.collection = self.db.quality_scores
        self.retention_days = 90  # 默认保留90天
        
        # 创建索引
        self._create_indexes()
    
    def _create_indexes(self):
        """创建索引"""
        try:
            # 内容ID索引
            self.collection.create_index([("content_id", pymongo.ASCENDING)])
            # 评估时间索引（用于清理过期数据）
            self.collection.create_index([("evaluated_at", pymongo.DESCENDING)])
            # 内容类型索引
            self.collection.create_index([("content_type", pymongo.ASCENDING)])
            # 复合索引：内容ID + 评估时间
            self.collection.create_index([
                ("content_id", pymongo.ASCENDING),
                ("evaluated_at", pymongo.DESCENDING)
            ])
            logger.info("Created indexes for quality_scores collection")
        except Exception as e:
            logger.warning(f"Failed to create indexes: {e}")
    
    async def save_score(self, score_history: ScoreHistory) -> str:
        """
        保存评分记录
        
        Args:
            score_history: 评分历史记录
            
        Returns:
            记录ID
        """
        try:
            # 转换为MongoDB文档格式
            document = score_history.to_mongo()
            
            # 插入文档
            result = await self.collection.insert_one(document)
            
            logger.info(f"Saved score for content_id: {score_history.content_id}")
            
            return str(result.inserted_id)
            
        except Exception as e:
            logger.error(f"Failed to save score: {e}")
            raise
    
    async def get_score_history(
        self,
        content_id: str,
        limit: int = 10,
        skip: int = 0
    ) -> List[ScoreHistory]:
        """
        获取评分历史
        
        Args:
            content_id: 内容ID
            limit: 返回记录数
            skip: 跳过记录数
            
        Returns:
            评分历史列表
        """
        try:
            # 查询条件
            query = {"content_id": content_id}
            
            # 查询并排序（最新的在前）
            cursor = self.collection.find(query).sort(
                "evaluated_at", pymongo.DESCENDING
            ).skip(skip).limit(limit)
            
            # 转换为模型对象
            history_list = []
            async for doc in cursor:
                history = ScoreHistory.from_mongo(doc)
                history_list.append(history)
            
            logger.debug(f"Retrieved {len(history_list)} score records for content_id: {content_id}")
            
            return history_list
            
        except Exception as e:
            logger.error(f"Failed to get score history: {e}")
            raise
    
    async def get_score_statistics(
        self,
        content_id: Optional[str] = None,
        content_type: Optional[str] = None,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None
    ) -> QualityMetrics:
        """
        获取评分统计
        
        Args:
            content_id: 内容ID（可选）
            content_type: 内容类型（可选）
            start_date: 开始时间（可选）
            end_date: 结束时间（可选）
            
        Returns:
            质量统计指标
        """
        try:
            # 构建查询条件
            query = {}
            if content_id:
                query["content_id"] = content_id
            if content_type:
                query["content_type"] = content_type
            if start_date or end_date:
                date_query = {}
                if start_date:
                    date_query["$gte"] = start_date
                if end_date:
                    date_query["$lte"] = end_date
                query["evaluated_at"] = date_query
            
            # 聚合统计
            pipeline = [
                {"$match": query},
                {
                    "$group": {
                        "_id": None,
                        "avg_score": {"$avg": "$scores.total_score"},
                        "count": {"$sum": 1},
                        "scores": {"$push": "$scores.total_score"},
                        "dimensions": {
                            "$push": "$scores.dimensions"
                        }
                    }
                }
            ]
            
            cursor = self.collection.aggregate(pipeline)
            result = await cursor.to_list(length=1)
            
            if not result:
                # 无数据时返回默认统计
                return QualityMetrics(
                    content_id=content_id,
                    average_score=0,
                    score_count=0,
                    dimension_averages={},
                    score_distribution={},
                    period_start=start_date,
                    period_end=end_date
                )
            
            stats = result[0]
            
            # 计算维度平均分
            dimension_averages = {}
            if stats.get("dimensions"):
                dimension_sums = {}
                dimension_counts = {}
                
                for dims in stats["dimensions"]:
                    for dim_name, dim_data in dims.items():
                        if dim_name not in dimension_sums:
                            dimension_sums[dim_name] = 0
                            dimension_counts[dim_name] = 0
                        dimension_sums[dim_name] += dim_data.get("score", 0)
                        dimension_counts[dim_name] += 1
                
                for dim_name in dimension_sums:
                    if dimension_counts[dim_name] > 0:
                        dimension_averages[dim_name] = dimension_sums[dim_name] / dimension_counts[dim_name]
            
            # 计算分数分布
            score_distribution = self._calculate_score_distribution(stats.get("scores", []))
            
            # 计算趋势
            trend = await self._calculate_trend(content_id, content_type)
            
            return QualityMetrics(
                content_id=content_id,
                average_score=stats.get("avg_score", 0),
                score_count=stats.get("count", 0),
                dimension_averages=dimension_averages,
                score_distribution=score_distribution,
                trend=trend,
                period_start=start_date,
                period_end=end_date
            )
            
        except Exception as e:
            logger.error(f"Failed to get score statistics: {e}")
            raise
    
    async def batch_save_scores(self, score_histories: List[ScoreHistory]) -> List[str]:
        """
        批量保存评分
        
        Args:
            score_histories: 评分历史列表
            
        Returns:
            记录ID列表
        """
        try:
            # 转换为文档列表
            documents = [score.to_mongo() for score in score_histories]
            
            # 批量插入
            result = await self.collection.insert_many(documents)
            
            logger.info(f"Batch saved {len(result.inserted_ids)} scores")
            
            return [str(id) for id in result.inserted_ids]
            
        except Exception as e:
            logger.error(f"Failed to batch save scores: {e}")
            raise
    
    async def clean_expired_scores(self, retention_days: Optional[int] = None) -> int:
        """
        清理过期评分数据
        
        Args:
            retention_days: 保留天数（默认90天）
            
        Returns:
            删除的记录数
        """
        try:
            days = retention_days or self.retention_days
            cutoff_date = datetime.utcnow() - timedelta(days=days)
            
            # 删除过期数据
            result = await self.collection.delete_many({
                "evaluated_at": {"$lt": cutoff_date}
            })
            
            deleted_count = result.deleted_count
            logger.info(f"Cleaned {deleted_count} expired score records (older than {days} days)")
            
            return deleted_count
            
        except Exception as e:
            logger.error(f"Failed to clean expired scores: {e}")
            raise
    
    async def get_latest_score(self, content_id: str) -> Optional[ScoreHistory]:
        """
        获取最新评分
        
        Args:
            content_id: 内容ID
            
        Returns:
            最新的评分记录
        """
        try:
            # 查询最新的一条记录
            doc = await self.collection.find_one(
                {"content_id": content_id},
                sort=[("evaluated_at", pymongo.DESCENDING)]
            )
            
            if doc:
                return ScoreHistory.from_mongo(doc)
            
            return None
            
        except Exception as e:
            logger.error(f"Failed to get latest score: {e}")
            raise
    
    async def update_score(self, score_id: str, updates: Dict[str, Any]) -> bool:
        """
        更新评分记录
        
        Args:
            score_id: 记录ID
            updates: 更新内容
            
        Returns:
            是否更新成功
        """
        try:
            # 添加更新时间
            updates["updated_at"] = datetime.utcnow()
            
            # 更新文档
            result = await self.collection.update_one(
                {"_id": ObjectId(score_id)},
                {"$set": updates}
            )
            
            success = result.modified_count > 0
            
            if success:
                logger.info(f"Updated score record: {score_id}")
            else:
                logger.warning(f"No score record found with id: {score_id}")
            
            return success
            
        except Exception as e:
            logger.error(f"Failed to update score: {e}")
            raise
    
    async def delete_score(self, score_id: str) -> bool:
        """
        删除评分记录
        
        Args:
            score_id: 记录ID
            
        Returns:
            是否删除成功
        """
        try:
            result = await self.collection.delete_one({"_id": ObjectId(score_id)})
            
            success = result.deleted_count > 0
            
            if success:
                logger.info(f"Deleted score record: {score_id}")
            else:
                logger.warning(f"No score record found with id: {score_id}")
            
            return success
            
        except Exception as e:
            logger.error(f"Failed to delete score: {e}")
            raise
    
    def _calculate_score_distribution(self, scores: List[float]) -> Dict[str, int]:
        """
        计算分数分布
        
        Args:
            scores: 分数列表
            
        Returns:
            分数分布字典
        """
        distribution = {
            "0-20": 0,
            "20-40": 0,
            "40-60": 0,
            "60-80": 0,
            "80-100": 0
        }
        
        for score in scores:
            if score < 20:
                distribution["0-20"] += 1
            elif score < 40:
                distribution["20-40"] += 1
            elif score < 60:
                distribution["40-60"] += 1
            elif score < 80:
                distribution["60-80"] += 1
            else:
                distribution["80-100"] += 1
        
        return distribution
    
    async def _calculate_trend(
        self,
        content_id: Optional[str] = None,
        content_type: Optional[str] = None
    ) -> str:
        """
        计算评分趋势
        
        Args:
            content_id: 内容ID
            content_type: 内容类型
            
        Returns:
            趋势（improving/declining/stable）
        """
        try:
            # 获取最近的评分记录
            query = {}
            if content_id:
                query["content_id"] = content_id
            if content_type:
                query["content_type"] = content_type
            
            # 获取最近10条记录
            cursor = self.collection.find(query).sort(
                "evaluated_at", pymongo.DESCENDING
            ).limit(10)
            
            scores = []
            async for doc in cursor:
                scores.append(doc.get("scores", {}).get("total_score", 0))
            
            if len(scores) < 3:
                return "stable"
            
            # 简单的趋势判断：比较前半部分和后半部分的平均值
            mid = len(scores) // 2
            recent_avg = sum(scores[:mid]) / mid
            older_avg = sum(scores[mid:]) / len(scores[mid:])
            
            diff = recent_avg - older_avg
            
            if diff > 5:
                return "improving"
            elif diff < -5:
                return "declining"
            else:
                return "stable"
                
        except Exception as e:
            logger.warning(f"Failed to calculate trend: {e}")
            return "stable"